
import { createAlovaMethod } from '@/apis/ApiRequest'
import { musicStore } from '@/stores/music-stores'

import type { Method } from 'alova'
import type { MusicStoreRecord } from '@/types/music'

const appInfo = {
  version: '2.11.0',
  env: 'desktop'
}

const IKUNConfig = {
  API_KEY: 'KAWANG_63b29688-GE5LEV8TPCJO4U6N'
}

const OfficialAccountConfig = {
  API_KEY: 'lxmusic'
}

// ======== 获取音乐下载链接 ======== //

export type BaseParams = {
  id: string | number
  source: string
  quality: string
}

type GetMusicUrlParams = BaseParams & {
  provider: string
}

const getMusicUrlApiList: {
  [key: string]: (params: GetMusicUrlParams) => ApiConfig
} = {
  ikun: () => ({
    url: 'https://music.ikun0014.top/url',
    method: 'GET',
    description: '获取歌曲链接',
    proxyPrefix: '',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    // follow_max: 5
  }),
  officialAccount: (params) => ({
    url: `https://88.lxmusic.xn--fiqs8s/url/${params.source}/${params.id}/${params.quality}`,
    method: 'GET',
    description: '获取歌曲链接',
    proxyPrefix: '',
    headers: {
      'Content-Type': 'application/json',
      'User-Agent': appInfo.env ? `lx-music-${appInfo.env}/${appInfo.version}` : `lx-music-request/${appInfo.version}`,
      'X-Request-Key': OfficialAccountConfig.API_KEY
    },
  })
}

const getMusicUrlApiParamsKeys: {
  [key: string]: BaseParams
} = {
  ikun: {
    id: 'songId',
    source: 'source',
    quality: 'quality'
  },
  officialAccount: {
    id: 'songId',
    source: 'source',
    quality: 'quality'
  },
}

const getMusicUrlApiParams = ({
  id,
  source,
  quality,
  provider,
}: GetMusicUrlParams) => {
  switch (provider) {
    case 'ikun':
      return {
        songId: id,
        source,
        quality
      }
    case 'officialAccount':
      return {}
    default:
      return {}
  }
}

/**
 * 获取音乐下载链接
 * @param provider api提供方
 * @param id 音乐id
 * @param source 音乐来源
 * @param quality 音乐质量
 * @returns AlovaMethod
 */
export const getMusicUrlMethod = ({
  id,
  source,
  quality,
  provider,
}: GetMusicUrlParams): Method => {
  return createAlovaMethod({
    api: getMusicUrlApiList[provider]({ id, source, provider, quality }),
    params: getMusicUrlApiParams({ id, source, quality, provider }),
    name: `get-music-url-${provider}`,
    // 进程间共享缓存适配器
    cacheFor: { mode: 'restore', expire: 1000 * 60 * 60 * 24, },
  })
}

// ======== 通过给定链接下载音乐 ======== //
const downloadMusicApi: ApiConfig = {
  url: '',
  method: 'GET',
  description: '下载歌曲',
  headers: {
    'Accept': '*/*'
  },
}

export type DownloadMusicParams = {
  url: string
  musicInfo: MusicStoreRecord
  quality: string
  provider?: string
}

type DownloadFileType = 'music' | 'cover' | 'lyric'

/**
 * 下载音乐
 * @url 音乐下载链接
 * @musicInfo 音乐信息用于存储在indexedDB中
 * @id 音乐id 联合主键之一
 * @source 音乐来源 联合主键之一
 * @quality 音乐质量 联合主键之一
 * @provider api提供方
 * @returns
 */
export const downloadMusicMethod = ({
  url,
  musicInfo,
  quality,
  provider
}: DownloadMusicParams): Method => createAlovaMethod({
  api: {
    ...downloadMusicApi,
    url: url,
    description: '下载音乐',
  },
  params: {},
  name: `download-music-${provider}`,
  cacheFor: async () => {
    return await downloadCacheFor({ id: musicInfo.id, source: musicInfo.source, quality }, 'music')
  },
  transform: async (data, _: Headers | unknown) => {
    return await downloadTransform({
      url, data, musicInfo, quality, provider
    }, 'music')
  }
})

/**
 * 下载封面
 * @url 封面链接
 * @musicInfo 音乐信息用于存储在indexedDB中
 * @id 音乐id 联合主键之一
 * @source 音乐来源 联合主键之一
 * @quality 音乐质量 联合主键之一
 * @returns
 */
export const downloadPictureMethod = ({
  url,
  musicInfo,
  quality,
}: DownloadMusicParams): Method => createAlovaMethod({
  api: {
    ...downloadMusicApi,
    url: url,
    description: '下载歌曲专辑封面',
  },
  params: {},
  name: 'download-picture',
  cacheFor: async () => {
    return await downloadCacheFor({ id: musicInfo.id, source: musicInfo.source, quality }, 'cover')
  },
  transform: async (data: unknown, _: Headers | unknown) => {
    return await downloadTransform({
      url, data, musicInfo, quality
    }, 'cover')
  }
})

/**
 * 从缓存中获取文件（音乐、封面、歌词）
 * @param id 音乐id 联合主键之一
 * @param source
 * @returns
 */
const downloadCacheFor = async ({
  id, source, quality
}: BaseParams, downloadFileType: DownloadFileType) => {
  const res = await new Promise((resolve, _) => {
    const union_key = `${id}-${source}-${quality}`
    musicStore.getMusic(union_key).then((record: MusicStoreRecord | undefined) => {
      if (record) {
        if (downloadFileType === 'music' && record.music_blob_list?.[quality]) {
          resolve(record.music_blob_list?.[quality])
        } else if (downloadFileType === 'cover' && record.cover_blob) {
          resolve(record.cover_blob)
        } else if (downloadFileType === 'lyric' && record.lyric) {
          resolve(record.lyric)
        } else {
          console.warn('Unknown downloadFileType: ', downloadFileType)
          resolve(undefined)
        }
      } else {
        console.warn('Could not find music in indexedDB')
        resolve(undefined)
      }
    })
  })
  return res
}

const downloadTransform = async ({
  url, data, musicInfo, quality, provider
}: DownloadMusicParams & { data: unknown }, downloadFileType: DownloadFileType): Promise<Blob | undefined> => {
  const fileBlob = await (data as Response)?.blob()
  await new Promise((resolve, _) => {
    musicInfo.union_key = `${musicInfo.id}-${musicInfo.source}-${quality}`
    if (downloadFileType === 'cover') {
      musicInfo.cover_blob = fileBlob
    } else if (downloadFileType === 'music') {
      musicInfo.provider = provider
      musicInfo.quality = quality
      musicInfo.music_url_list = musicInfo.music_url_list || {}
      musicInfo.music_blob_list = musicInfo.music_blob_list || {}
      musicInfo.music_url_list[quality] = url
      musicInfo.music_blob_list[quality] = fileBlob
    }
    musicStore.saveMusic(musicInfo).then(() => {
      console.info(`保存成功：${musicInfo.artist?.join(' / ')}-${musicInfo.name}.${url.split('.').pop()}`)
      resolve(fileBlob)
    })
  })
  return fileBlob
}
